﻿using AutoMapper;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using NLog;
using ShenNius.Caches;
using ShenNius.Mvc.Admin.Common;
using ShenNius.Repository;
using ShenNius.Sys.API.Domain.Entity;
using ShenNius.Sys.API.Domain.Repository;
using ShenNius.Sys.API.Domain.Service;
using ShenNius.Sys.API.Domain.ValueObjects;
using ShenNius.Sys.API.Domain.ValueObjects.Enums;
using ShenNius.Sys.API.Dtos.Input;
using ShenNius.Sys.API.Dtos.Output;
using ShenNius.Sys.API.Hubs;
using ShenNius.Sys.API.Infrastructure;
using ShenNius.Sys.API.Infrastructure.Common;
using ShenNius.Sys.API.Infrastructure.Configs;
using ShenNius.Sys.API.Infrastructure.Extension;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace ShenNius.Mvc.Admin.Areas.Sys.Controllers
{
    [Area("sys")]
    public partial class UserController : Controller
    {
        private readonly IDistributedCache _cacheHelper;
        private readonly ICurrentUserContext _currentUserContext;
        private readonly IBaseRepository<User> _userRepository;
        private readonly IMenuRepository _menuRepository;
        private readonly IMapper _mapper;
        private readonly LoginDomainService _loginDomainService;
        private readonly UserLoginNotifiHub _userLoginNotifiHub;
        private readonly IBaseRepository<Config> _configRepository;

        public UserController(IDistributedCache cacheHelper, ICurrentUserContext currentUserContext, IBaseRepository<User> userRepository, IMenuRepository menuRepository, IMapper mapper, LoginDomainService loginDomainService, UserLoginNotifiHub userLoginNotifiHub, IBaseRepository<Config> configRepository)
        {
            _configRepository = configRepository;
            _cacheHelper = cacheHelper;
            _currentUserContext = currentUserContext;
            _userRepository = userRepository;
            _menuRepository = menuRepository;
            _mapper = mapper;
            _loginDomainService = loginDomainService;
            _userLoginNotifiHub = userLoginNotifiHub;
        }
        /// <summary>
        /// 用户首页列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult Index()
        {
            return View();
        }
        /// <summary>
        /// 设置角色
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult SetRole(int id)
        {
            ViewBag.UserId = id;
            return View();
        }
        [HttpGet]
        public async Task<IActionResult> Modify(int id = 0)
        {
            User model = null;
            if (id == 0)
            {
                model = new User();
            }
            else
            {
                model = await _userRepository.GetModelAsync(d => d.Id == id && d.IsDeleted == false);
            }
            return View(model);
        }
        [HttpGet]
        public IActionResult ModifyPwd()
        {
            return View();
        }

        [HttpGet]
        public IActionResult CurrentUserInfo()
        {
            UserOutput userOutput = new UserOutput();
            if (HttpContext.User.Identity.IsAuthenticated)
            {
                userOutput.Name = HttpContext.User.Identity.Name;
                userOutput.Id = Convert.ToInt32(HttpContext.User.Claims.Where(d => d.Type == JwtRegisteredClaimNames.Sid).Select(d => d.Value).FirstOrDefault());
                userOutput.Mobile = HttpContext.User.Claims.Where(d => d.Type == "mobile").Select(d => d.Value).FirstOrDefault();
                userOutput.Email = HttpContext.User.Claims.Where(d => d.Type == ClaimTypes.Email).Select(d => d.Value).FirstOrDefault();
                userOutput.TrueName = HttpContext.User.Claims.Where(d => d.Type == "trueName").Select(d => d.Value).FirstOrDefault();
            }
            else
            {
                Redirect("/user/login");
            }
            return View(userOutput);
        }
        [HttpGet, AllowAnonymous]
        public async Task<IActionResult> Login()
        {
            var rsaKey = RSACrypt.GetKey();
            var number = Guid.NewGuid().ToString();
            if (rsaKey.Count <= 0 || rsaKey == null)
            {
                throw new ArgumentNullException("获取登录的公钥和私钥为空");
            }
            ViewBag.RsaKey = rsaKey[0];
            ViewBag.Number = number;
            //获得公钥和私钥
            _cacheHelper.Set($"{SysCacheKey.EncryLoginKey}:{number}", rsaKey);
            var value = await SysSetting.ReadAsync();
            return View(value);
        }

        [HttpPost, AllowAnonymous]
        public async Task<ApiResult<LoginOutput>> Login([FromBody] LoginInput loginInput)
        {
            try
            {
                var rsaKey = _cacheHelper.Get<List<string>>($"{SysCacheKey.EncryLoginKey}:{loginInput?.NumberGuid}");
                if (rsaKey == null)
                {
                    throw new ArgumentException("登录失败，请刷新浏览器再次登录!");
                }
                var ras = new RSACrypt(rsaKey[0], rsaKey[1]);
                loginInput.Password = ras.Decrypt(loginInput.Password);

                var result = await _loginDomainService.LoginAsync(loginInput);
                if (result.StatusCode == 500 || result.StatusCode == 200 && result.Success == false)
                {
                    result.Data = new LoginOutput();
                    return result;
                }
                //请求当前用户的所有权限并存到缓存里面并发给前端 准备后面鉴权使用
                var menuAuths = await _menuRepository.GetCurrentAuthMenus(result.Data.Id);
                if (menuAuths == null || menuAuths.Count == 0)
                {
                    return new ApiResult<LoginOutput>("不好意思，该用户当前没有权限。请联系系统管理员分配权限！");
                }
                result.Data.MenuAuthOutputs = menuAuths;
                if (loginInput.ConfirmLogin)
                {
                    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
                    _cacheHelper.Remove($"{SysCacheKey.AuthMenu}:{_currentUserContext.Id}");
                }
                var identity = new ClaimsPrincipal(
                   new ClaimsIdentity(new[]
                       {
                              new Claim(JwtRegisteredClaimNames.Sid,result.Data.Id.ToString()),
                              new Claim(ClaimTypes.Name,result.Data.LoginName),
                              new Claim(ClaimTypes.WindowsAccountName,result.Data.LoginName),
                              new Claim(ClaimTypes.UserData,result.Data.LastLoginTime.ToString()),
                              new Claim(ClaimTypes.Email,result.Data.Mobile),
                              new Claim("trueName",result.Data.TrueName)
                       }, CookieAuthenticationDefaults.AuthenticationScheme)
                  );
                await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, identity, new AuthenticationProperties
                {
                    ExpiresUtc = DateTime.UtcNow.AddHours(24),
                    IsPersistent = true,
                    AllowRefresh = false
                });
                _cacheHelper.Remove($"{SysCacheKey.EncryLoginKey}:{loginInput.NumberGuid}");
                new LogHelper().Process(loginInput.LoginName, LogEnum.Login.GetEnumText(), $"登陆成功", LogLevel.Info);
                return result;
            }
            catch (Exception ex)
            {
                ApiResult<LoginOutput> result = new ApiResult<LoginOutput>(msg: $"登陆失败！{ex.Message}");
                new LogHelper().Process(loginInput.LoginName, LogEnum.Login.GetEnumText(), $"登陆失败:{ex.Message}", LogLevel.Error, ex);
                return result;
            }
        }


        [HttpGet, AllowAnonymous]
        public FileResult OnGetVCode()
        {
            var vcode = VerifyCode.CreateRandomCode(4);
            HttpContext.Session.SetString("vcode", vcode);
            var img = VerifyCode.DrawImage(vcode, 20, Color.White);
            return File(img, "image/gif");
        }

        [HttpGet]
        public async Task<ApiResult> Logout()
        {
            try
            {
                await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
                _cacheHelper.Remove($"{SysCacheKey.AuthMenu}:{_currentUserContext.Id}");
                new LogHelper().Process(_currentUserContext.Name, LogEnum.Login.GetEnumText(), $"{_currentUserContext.Name}成功退出系统!", LogLevel.Info);
                //设置用户退出
                await _userRepository.UpdateAsync(d => new User() { IsLogin = false }, d => d.Id == _currentUserContext.Id);
                _userLoginNotifiHub.Clear();
                return new ApiResult();
            }
            catch
            {
                return new ApiResult("退出失败了！");
            }
        }

    }
}
